package
{
	import flash.display.*;
	import flash.errors.IllegalOperationError;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	/** Used for dragging points around */
	public class DragTool extends CursorTool
	{
		
		// private objects
		private var drawPoints:Array = null;
		private var oobshapes:Array = null;
		private var overDrawPoint:DrawPoint = null;
		private var selectedDrawPoint:DrawPoint = null;
		// private vars
		private var _state:String;
		private var dragging_point:Boolean = false;
		private var _outOfBounds:Boolean = false;
		override public function get outOfBounds():Boolean{return _outOfBounds;}
		override public function get components():Array
		{
			if (selectedDrawPoint != null)
			{
				return new Array(selectedDrawPoint);
			}  else if (overDrawPoint != null)
			{
				return new Array(overDrawPoint);
			}else
			{
				return null;
			}
		}
		
		public function DragTool(drawPoints:Array, oobshapes:Array)
		{
			super(this);
			this.drawPoints = drawPoints;
			this.oobshapes = oobshapes;
			this.mouseEnabled = false;
			this.mouseChildren = false;
			this.addEventListener(Event.ADDED, handleAdded);
		}
		private function handleAdded(event:Event):void
		{
			this.removeEventListener(Event.ADDED, handleAdded);
			_state = "drag";
			drawCursor();
			// go through each point and add event listener
			for each (var p:DrawPoint in drawPoints)
			{
				p.mouseEnabled = true;
				if(!p.hasEventListener(MouseEvent.MOUSE_OVER)) p.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverPoint);
			}
			for each (var oobshape:OobShape in oobshapes)
			{
				oobshape.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOobShape);				
			}
			this.addEventListener(Event.REMOVED, handleRemoved);			
		}
		
		/** Mouse over should work for all points to highlight except currently selected, unless allow disconnected */
		private function handleMouseOverPoint(event:MouseEvent):void
		{
			overDrawPoint = DrawPoint(event.currentTarget);
			overDrawPoint.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverPoint);
			// If this point is not selected, wait for press in drag_mode wait, for click in non_drag mode
			if (!overDrawPoint.pinned)
			{
				_state = "drag-yes";
				overDrawPoint.enhance = true;
				overDrawPoint.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownPoint);
			} else
			{
				_state = "drag-no";				
			} 
			drawCursor();
			overDrawPoint.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOutPoint);
		}
		private function handleMouseOutPoint(event:MouseEvent):void
		{
			overDrawPoint.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutPoint);
			// in the case where the point we are over is highlighted remove the clicking potential and change back highlighting				
			overDrawPoint.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownPoint);
			overDrawPoint.enhance = false;
			if (!dragging_point)
			{
				_state = "drag";
				drawCursor();			
			} 
			overDrawPoint.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverPoint);
			overDrawPoint = null;
		}
		
		/** For dragging of point in drag_mode */
		private function handleMouseDownPoint(event:MouseEvent):void
		{
			overDrawPoint.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownPoint);
			// There is a point selected, draw a new segment to the overpoint, or if overpoint is the same selected, (if allowed) deselect it
			//trace("mouse down", overDrawPoint, selectedDrawPoint);
			if (overDrawPoint != selectedDrawPoint)
			{
				if (selectedDrawPoint != null)selectedDrawPoint.highlight = false;
				selectedDrawPoint = overDrawPoint;
				selectedDrawPoint.highlight = true;
				//DrawingPanel(parent).selectPoint(overDrawPoint);
			}		
			if (!selectedDrawPoint.pinned)
			{
				dragging_point = true;
				// we need to make this unenabled so that we can tell if we go over an oobshape
				selectedDrawPoint.mouseEnabled = false;
			}
			this.stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUpPoint);			
		}
		/** For dragging of point in drag_mode */
		private function handleMouseUpPoint(event:MouseEvent):void
		{
			this.stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUpPoint);
			dragging_point = false;
			selectedDrawPoint.mouseEnabled = true;
			if (overDrawPoint != null)
			{
				overDrawPoint.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownPoint);				
			}
			selectedDrawPoint.highlight = false;	
			GeometryGameItem(parent.parent).processCommand("drag", "in_progress", this);
			selectedDrawPoint = null;
			
		}
		
		// out of bounds objects
		private function handleMouseOverOobShape(event:MouseEvent):void
		{
			event.currentTarget.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOobShape);
			_outOfBounds = true;
			if (this.dragging_point)
			{
				_state = "drag-no";
				drawCursor();
			}
			event.currentTarget.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOobShape);
		}
		private function handleMouseOutOobShape(event:MouseEvent):void
		{
			event.currentTarget.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOobShape);
			_outOfBounds = false;
			if (this.dragging_point)
			{
				_state = "drag-yes";
				drawCursor();
			}
			event.currentTarget.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOobShape);
		}
		
		/** process moves cursor, looks for out of bounds shapes */
		override public function process(point:Point):void
		{			
			this.x = point.x;
			this.y = point.y;
			//trace(dragging_point, selectedDrawPoint);
			if (dragging_point && selectedDrawPoint != null)
			{				
				if (!_outOfBounds)
				{	
					if (selectedDrawPoint.moveTo(point.x, point.y))
					{
						//trace(selectedDrawPoint.id, points.length);
						/*
						for each (var s:DrawSegment in selectedDrawPoint.drawSegments)
						{
							s.redraw(selectedDrawPoint);
							
							for each (var a:DrawAngle in s.point1.drawAngles)
							{
								a.redraw(selectedDrawPoint);
							}
							for each (a in s.point2.drawAngles)
							{
								a.redraw(selectedDrawPoint);
							}
						}
						*/
					}
				}
			}
		}
		
		/** Draws a hand cursor to indicate the polygon being selected */
		private function drawCursor():void
		{
			// for drag
			var cdenom:Number = 1*ShapeProductionTask.unit;
			var adenom:Number = 3*ShapeProductionTask.unit;
			var pointsize:Number = DrawPoint.POINT_SIZE*ShapeProductionTask.unit;
			var enhancedsize:Number = DrawPoint.ENHANCED_SIZE*ShapeProductionTask.unit;
			
			this.graphics.clear();
			switch (_state)
			{	
				case "drag":
				this.graphics.clear();
				this.graphics.lineStyle(1,0x000000);
				this.graphics.moveTo(0,-pointsize/cdenom);
				this.graphics.lineTo(0,pointsize/cdenom);
				this.graphics.moveTo(-pointsize/cdenom,0);
				this.graphics.lineTo(pointsize/cdenom,0);
				//arrowheads
				this.graphics.lineStyle(2,0x000000);
				//top
				this.graphics.moveTo(0,-pointsize/cdenom);
				this.graphics.lineTo(-pointsize/adenom,-pointsize/cdenom+pointsize/adenom);
				this.graphics.moveTo(0,-pointsize/cdenom);
				this.graphics.lineTo(pointsize/adenom,-pointsize/cdenom+pointsize/adenom);
				//bottom
				this.graphics.moveTo(0,pointsize/cdenom);
				this.graphics.lineTo(-pointsize/adenom,pointsize/cdenom-pointsize/adenom);
				this.graphics.moveTo(0,pointsize/cdenom);
				this.graphics.lineTo(pointsize/adenom,pointsize/cdenom-pointsize/adenom);
				//left
				this.graphics.moveTo(-pointsize/cdenom,0);
				this.graphics.lineTo(-pointsize/cdenom+pointsize/adenom,-pointsize/adenom);
				this.graphics.moveTo(-pointsize/cdenom,0);
				this.graphics.lineTo(-pointsize/cdenom+pointsize/adenom, pointsize/adenom);
				//right
				this.graphics.moveTo(pointsize/cdenom,0);
				this.graphics.lineTo(pointsize/cdenom-pointsize/adenom,-pointsize/adenom);
				this.graphics.moveTo(pointsize/cdenom,0);
				this.graphics.lineTo(pointsize/cdenom-pointsize/adenom, pointsize/adenom);
				break;	
				case "drag-yes":
				this.graphics.clear();
				this.graphics.lineStyle(1,0x000000);
				this.graphics.drawEllipse(-pointsize/2, -pointsize/2, pointsize, pointsize);
				//arrowheads
				this.graphics.lineStyle(2,0x000000);
				//top
				this.graphics.moveTo(0,-pointsize/cdenom);
				this.graphics.lineTo(-pointsize/adenom,-pointsize/cdenom+pointsize/adenom);
				this.graphics.moveTo(0,-pointsize/cdenom);
				this.graphics.lineTo(pointsize/adenom,-pointsize/cdenom+pointsize/adenom);
				//bottom
				this.graphics.moveTo(0,pointsize/cdenom);
				this.graphics.lineTo(-pointsize/adenom,pointsize/cdenom-pointsize/adenom);
				this.graphics.moveTo(0,pointsize/cdenom);
				this.graphics.lineTo(pointsize/adenom,pointsize/cdenom-pointsize/adenom);
				//left
				this.graphics.moveTo(-pointsize/cdenom,0);
				this.graphics.lineTo(-pointsize/cdenom+pointsize/adenom,-pointsize/adenom);
				this.graphics.moveTo(-pointsize/cdenom,0);
				this.graphics.lineTo(-pointsize/cdenom+pointsize/adenom, pointsize/adenom);
				//right
				this.graphics.moveTo(pointsize/cdenom,0);
				this.graphics.lineTo(pointsize/cdenom-pointsize/adenom,-pointsize/adenom);
				this.graphics.moveTo(pointsize/cdenom,0);
				this.graphics.lineTo(pointsize/cdenom-pointsize/adenom, pointsize/adenom);
				break;
				case "drag-no":
				this.graphics.clear();
				this.graphics.lineStyle(1,0x000000);
				this.graphics.drawEllipse(-pointsize/2, -pointsize/2, pointsize, pointsize);
				this.graphics.lineStyle(1.5,0xFF0000);
				this.graphics.moveTo(-enhancedsize/2*Math.sqrt(2)/2,-enhancedsize/2*Math.sqrt(2)/2);
				this.graphics.lineTo(enhancedsize/2*Math.sqrt(2)/2,enhancedsize/2*Math.sqrt(2)/2);
				this.graphics.moveTo(enhancedsize/2*Math.sqrt(2)/2,-enhancedsize/2*Math.sqrt(2)/2);
				this.graphics.lineTo(-enhancedsize/2*Math.sqrt(2)/2,enhancedsize/2*Math.sqrt(2)/2);
				break;
			}
		}
		
		/** On removal unproject and unoutline */
		private function handleRemoved(event:Event):void
		{
			this.removeEventListener(Event.REMOVED, handleRemoved);
			if (overDrawPoint != null)
			{
				overDrawPoint.enhance = false;
				overDrawPoint.highlight = false;
			}
			if (selectedDrawPoint != null)
			{
				selectedDrawPoint.enhance = false;
				selectedDrawPoint.highlight = false;
			}
			for each (var p:DrawPoint in drawPoints)
			{
				if(p.hasEventListener(MouseEvent.MOUSE_OVER)) p.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverPoint);
				if(p.hasEventListener(MouseEvent.MOUSE_OUT)) p.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutPoint);
				if(p.hasEventListener(MouseEvent.MOUSE_DOWN)) p.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDownPoint);
				if(p.hasEventListener(MouseEvent.MOUSE_UP)) p.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUpPoint);
				p.mouseEnabled = false;
			}
			for each (var oobshape:OobShape in oobshapes)
			{
				if(oobshape.hasEventListener(MouseEvent.MOUSE_OVER)) oobshape.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOobShape);				
				if(oobshape.hasEventListener(MouseEvent.MOUSE_OUT)) oobshape.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOobShape);				
			}
			
		}
	}
}